<template>
  <div class="my-select">
    <my-input
      :readonly="true"
      :value="selectedValue"
      :disabled="disabled"
      :placeholder="placeholder"
      @focus="handleFocus"
      suffix-icon="arrow-down"
    ></my-input>
    <transition name="my-select-fade">
      <div class="my-select-dropdown" ref="dropdown" :style="dropdownStyle" v-show="show">
        <div class="my-select-dropdown__arrow"></div>
        <ul class="my-select-dropdown__list">
          <slot></slot>
        </ul>
      </div>
    </transition>
  </div>
</template>

<script>
import Input from "../input";
export default {
  name: "MySelect",
  components: {
    "my-input": Input,
  },
  props: {
    value: {
      required: true,
      type: String | Number | Array,
    },
    disabled: Boolean,
    multiple: Boolean,
    placeholder: {
      default: "请选择",
      type: String,
    },
  },
  provide() {
    return {
      select: this,
    };
  },
  data() {
    return {
      show: false,
      dropdownStyle: {},
      selectedValue: "",
      options: [],
    };
  },
  watch: {
    value: {
      handler() {
        this.$nextTick(() => {
          this.setSelected();
        });
      },
    },
  },
  mounted() {
    this.updateOptions();
    document.body.appendChild(this.$refs.dropdown);
    this.$on("handleOptionClick", this.handleOptionClick);
  },
  beforeDestroy() {
    document.body.removeChild(this.$refs.dropdown);
  },
  methods: {
    handleOptionClick({ value }) {
      if (this.multiple) {
        let valueArr = this.value;
        let index = valueArr.indexOf(value);
        if (index === -1) {
          valueArr.push(value);
        } else {
          valueArr.splice(index, 1);
        }
        this.$emit("input", valueArr);
      } else {
        this.$emit("input", value);
        this.close();
      }
    },
    setSelected() {
      let { value, multiple, options } = this;
      if (multiple) {
        let sOptions = options.filter((o) => value.indexOf(o.value) !== -1);
        this.selectedValue = sOptions.map((o) => o.label).join("，");
      } else {
        let option = options.find((o) => o.value === value);
        this.selectedValue = option ? option.label : "";
      }
    },
    open() {
      this.show = true;
      this.$nextTick(() => {
        this.calcDropdownStyle();
        this.addListeners();
      });
    },
    close() {
      this.show = false;
      this.$nextTick(() => {
        this.removeListeners();
      });
    },
    calcDropdownStyle() {
      let { height, width, top, left } = this.$el.getBoundingClientRect();
      let { scrollY, scrollX } = window;
      return (this.dropdownStyle = {
        width: `${width}px`,
        top: `${height + top + scrollY + 12}px`,
        left: `${left + scrollX}px`,
      });
    },
    handleFocus() {
      this.open();
    },
    handleBlur() {
      //   this.close();
    },
    updateOptions() {
      let options = this.$slots.default
        ? this.$slots.default.map((o) => o.componentInstance)
        : [];
      this.options = options.filter((o) => !!o);
      this.setSelected();
    },
    handleClickDocument(e) {
      if (this.$el && (this.$el === e.target || this.$el.contains(e.target))) {
        return;
      }
      if (
        this.$refs.dropdown &&
        (this.$refs.dropdown === e.target ||
          this.$refs.dropdown.contains(e.target))
      ) {
        return;
      }
      this.close();
    },
    addListeners() {
      window.addEventListener("resize", this.calcDropdownStyle);
      document.addEventListener("click", this.handleClickDocument);
    },
    removeListeners() {
      window.removeEventListener("resize", this.calcDropdownStyle);
      document.removeEventListener("click", this.handleClickDocument);
    },
  },
};
</script>

<style lang="scss">
.my-select {
  position: relative;
}

.my-select-dropdown {
  position: absolute;
  background-color: #ffffff;
  box-shadow: 0px 0px 20px 0px rgb(0 0 0 / 15%);
  font-size: 13px;
  border-radius: 6px;
  z-index: 1080;
  transition: opacity 0.2s, transform 0.2s;
  transform-origin: center top;

  .my-select-dropdown__arrow,
  .my-select-dropdown__arrow::after {
    position: absolute;
    width: 0;
    height: 0;
    border-style: solid;
    border-color: transparent;
    border-width: 6px;
  }
  .my-select-dropdown__arrow {
    left: 10%;
    top: -12px;
    border-bottom-color: #ffffff;
  }
}

.my-select-dropdown__list {
  list-style: none;
  padding: 6px 0;
  margin: 0;
}

.my-select-dropdown__item {
  display: block;
  position: relative;
  outline: none;
  padding: 10px 15px;
  color: #3f4254;
  cursor: pointer;
  transition: 0.15s ease;

  &:not(.disabled):hover {
    background-color: #f3f6f9;
  }

  &.selected {
    color: #00b2ff;
    font-weight: bold;
  }

  &.disabled {
    color: #b5b5c3;
    cursor: not-allowed;
  }
}

.my-select-fade-enter,
.my-select-fade-leave-active {
  opacity: 0;
  transform: scaleY(0);
}
</style>